﻿using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Chat
{
    public partial class Chat : Form
    {
        private string username = "Unknown";
        private StreamWriter Send;
        private StreamReader Recieve;
        private TcpClient tcpServer;

        //vangt berichten van andere threads af
        private delegate void updateLogCallback(string message);

        //vangt disconnects af
        private delegate void closeConnectionCallback(string reason);

        //thread waar je berichten mee binnenkrijgt
        private Thread threadMessaging;
        
        //ip port en connectiestatus (standaard false)
        private IPAddress ip;
        private int port;
        private Boolean connected;

        public Chat()
        {
            //als de applicatie afgesloten word zonder op disconnect te drukken moet er gedisconnect worden
            Application.ApplicationExit += new EventHandler(OnApplicationExit);
            InitializeComponent();
        }

        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (connected == true)
            {
                //close alles
                connected = false;
                Send.Close();
                Recieve.Close();
                tcpServer.Close();
            }
        }

        private void buttonConnect_Click(object sender, EventArgs e)
        {
            if (connected == false)
            {
                InitConnection();
            }
            else
            {
                CloseConnection("Disconnected by user");
            }
        }

        private void btnChatserver_Click(object sender, EventArgs e)
        {
            ChatServer.ChatServer chatserver = new ChatServer.ChatServer();
            chatserver.Show();
        }

        private void InitConnection()
        {
            //username, port en ip adres ophalen uit form
            ip = IPAddress.Parse(txtIp.Text);
            port = Convert.ToInt32(txtPort.Text);
            username = txtUsername.Text;

            //connectie maken met verkregen variabelen
            tcpServer = new TcpClient();
            tcpServer.Connect(txtIp.Text, port);

            //indien we connected zijn -> connected = true
            connected = true;

            //fields disabelen, message versturen enablen
            txtIp.Enabled = false;
            txtPort.Enabled = false;
            txtUsername.Enabled = false;
            buttonSend.Enabled = true;
            txtMessage.Enabled = true;
            buttonConnect.Text = "Disconnect";
            txtChat.ReadOnly = true;

            //username naar server sturen
            Send = new StreamWriter(tcpServer.GetStream());
            Send.WriteLine(username);
            Send.Flush();

            //thread starten waar je berichten mee binnen krijgt
            threadMessaging = new Thread(new ThreadStart(RecieveMessages));
            threadMessaging.Start();
        }

        private void RecieveMessages()
        {
            //berichten van de server verkrijgen
            Recieve = new StreamReader(tcpServer.GetStream());

            //controleren of we connected zijn, als we een 1 doorkrijgen zijn we connected
            string connectionResponse = Recieve.ReadLine();

            if (connectionResponse[0] == '1')
            {
                //doorgeven dat we connected zijn
                this.Invoke(new updateLogCallback(this.UpdateLog), new object[] { "Connected!" });
            }
            else //als we niet connected zijn
            {
                string Reason = "Connection failed!";
                 
                //reden uit response message van de server halen, deze bevind zich op nummer 3
                Reason += connectionResponse.Substring(2, connectionResponse.Length - 2);
                
                //form updaten met de reden
                this.Invoke(new closeConnectionCallback(this.CloseConnection), new object[] {Reason});

                //exit
                return;
            }

            while (connected == true)
            {
                try
                {
                    //laat messages in textbox zien
                    this.Invoke(new updateLogCallback(this.UpdateLog), new object[] { Recieve.ReadLine() });
                }
                catch
                {

                }
            }
        }

        //wordt aangeroepen door een andere thread. update de textbox
        private void UpdateLog(string Message)
        {
            txtChat.AppendText(Message+"\r\n");
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            SendMessage();
        }

        private void txtMessage_KeyPress(object Sender, KeyPressEventArgs e)
        {
            //enter toets = send
            if (e.KeyChar == (char)13)
            {
                SendMessage();
            }
        }

        private void SendMessage()
        {
            if (txtMessage.Lines.Length >= 1)
            {
                Send.WriteLine(txtMessage.Text);
                Send.Flush();
                txtMessage.Lines = null;
            }

            //nadat het bericht verstuurd is moet het veld leeg zijn
            txtMessage.Text = "";
        }

        private void CloseConnection(string Reason)
        {
            //reden van disconnect sturen
            txtMessage.AppendText(Reason+"\r\n");

            //velden enablen / disablen
            txtIp.Enabled = true;
            txtPort.Enabled = true;
            txtUsername.Enabled = true;
            buttonSend.Enabled = false;
            txtMessage.Enabled = false;
            buttonConnect.Text = "Connect";

            //objecten sluiten
            connected = false;
            Send.Close();
            Recieve.Close();
            tcpServer.Close();
        }
    }
}